﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ClickLand.CorporacionPlaza.Comunes.Entidades;
using ClickLand.CorporacionPlaza.Comunes.Recursos;
using ClickLand.CorporacionPlaza.LogicaNegocio.Contratos;
using ClickLand.CorporacionPlaza.LogicaNegocio.Fabricas;
using Logger;


namespace ClickLand.CorporacionPlaza.LogicaNegocio.Logica
{
    /// <summary> Clase que implementa el contrato para las operaciones logica en la aplicacion </summary>
    public class LogicaCorporacionPlaza:ILogicaCorporacionPlaza
    {
        /// <summary> Metodo que realiza la prueba de la aplicacion </summary>
        /// <returns>true si es valido false sino</returns>
        public bool Prueba()
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<bool> comando = FabricaComandosPrueba.ObtenerComandoPrueba();
            var retorno = comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;

        }


        /// <summary> Metodo que almacena los datos de un cliente </summary>
        /// <param name="cliente">datos del cliente a almacenar</param>
        /// <returns>true si la transaccion fue exitosa false sino</returns>
        public bool AgregarEditarCliente(Cliente cliente)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<bool> comando = FabricaComandosCliente.ObtenerComandoAgregarEditar(cliente);
            var retorno = comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metodo que consulta los clientes dados los parametros indicados </summary>
        /// <param name="parametros">datos para la consulta</param>
        /// <returns>lista de cliente</returns>
        public List<Cliente> ConsultarCliente(Cliente parametros)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<List<Cliente>> comando = FabricaComandosCliente.ConsultarCliente(parametros);
            var retorno = comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metodo que agrega o modifica los datos de un establecimiento </summary>
        /// <param name="establecimiento"></param>
        /// <returns></returns>
        public bool AgregarEditarEstablecimiento(Establecimiento establecimiento)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<bool> comando = FabricaComandosEstablecimiento.ObtenerComandoAgregarEditar(establecimiento);
            var retorno = comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metodo que Consulta los establecimientos </summary>
        /// <param name="establecimiento"> </param>
        /// <returns>Lista de todos los establecimientos</returns>
        public List<Establecimiento> ConsultarTodosEstablecimientos(Establecimiento establecimiento)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<List<Establecimiento>> comando = FabricaComandosEstablecimiento.ObtenerComandoConsultarTodos(establecimiento);
            var retorno = comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion

            return retorno;
        }


        /// <summary> Metodo que agrega o modifica los datos de un contrato </summary>
        /// <param name="contrato"> datos del contrato a insertar o modificar</param>
        /// <returns>true si realizo la insercion/Modificacion </returns>
        public bool AgregarEditarContrato(Contrato contrato)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<bool> comando = FabricaComandosContrato.ObtenerComandoAgregar(contrato);
            var retorno = comando.Ejecutar();
            if(retorno)
            {
                IComando<bool> comandoEditar = FabricaComandosCliente.ObtenerComandoAgregarEditar(contrato.Cliente);
                comandoEditar.Ejecutar();

                foreach (var poliza in contrato.Polizas)
                {
                    poliza.Contratos = new List<Contrato>();
                    poliza.Contratos.Add(contrato);
                    comando = FabricaComandosPoliza.ObtenerComandoAgregarEditar(poliza);
                    comando.Ejecutar();
                }
            }
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metodo que consulta los datos de un contrato </summary>
        /// <param name="entidad">Parametros para la busqueda</param>
        /// <returns>Lista de contratos</returns>
        public IList<Contrato> ConsultarContrato(Contrato entidad)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<IList<Contrato>> comando = FabricaComandosContrato.ObtenerComandoConsultar(entidad);
            var lista = comando.Ejecutar();

            foreach (var contrato in lista)
            {
                IComando<Cliente> comandoCliente = FabricaComandosCliente.ObtenerComandoConsultarId(contrato.Cliente.Id);
                contrato.Cliente = comandoCliente.Ejecutar();

                IComando<Establecimiento> comandoEstablecimiento =
                    FabricaComandosEstablecimiento.ObtenerComandoConsultarId(contrato.Establecimiento.Id);
                contrato.Establecimiento = comandoEstablecimiento.Ejecutar();
                contrato.Fiadores = FabricaComandosFiador.ObtenerComandoConsultarPorContrato(contrato.Id).Ejecutar();
                contrato.Pension = FabricaComandosPension.ObtenerComandoConsultarPorContrato(contrato.Id).Ejecutar();
                contrato.Pension.ContratoPensiones =
                    FabricaComandosContratoPension.ObtenerComandoConsultarLista(contrato.Pension.Id).Ejecutar();
                contrato.Polizas = FabricaComandosPoliza.ObtenerComandoConsultarLista(contrato.Id).Ejecutar();
            }

            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return lista;
        }

        /// <summary> Metodo que consulta un contato por su id </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Contrato ConsultarContrato(long id)
        {

            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<Contrato> comando = FabricaComandosContrato.ObtenerComandoConsultarId(id);
            var retorno = comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metodo que envia los correo en el caso de los contratos </summary>
        /// <param name="lista">lista de contratos activos</param>
        private void EnviarCorreoContratos(IEnumerable<Contrato> lista)
        {

            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion

            foreach (var contrato in lista)
            {
                TimeSpan ts = contrato.FechaFin - DateTime.Now;

                // Difference in days.
                int dias = ts.Days;

                if ((dias - 90) == 0)
                    FabricaComandosContrato.ObtenerComandoEnviarCorreo(dias, contrato).Ejecutar();
                else if ((dias - 60) == 0)
                    FabricaComandosContrato.ObtenerComandoEnviarCorreo(dias, contrato).Ejecutar();
                else if (dias <= 30)
                    FabricaComandosContrato.ObtenerComandoEnviarCorreo(dias, contrato).Ejecutar();
            }

            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion
        }


        /// <summary> Metodo que envia los correo en el caso de las polizas </summary>
        /// <param name="lista">lista de contratos activos</param>
        private void EnviarCorreoPolizas(IEnumerable<Contrato> lista)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion

            foreach (var contrato in lista)
            {
                foreach (int dias in from poliza in contrato.Polizas 
                                     where poliza.FechaEmision <= DateTime.Now && poliza.FechaFin >= DateTime.Now 
                                     select poliza.FechaFin - DateTime.Now into ts select ts.Days)
                {
                    if ((dias - 60) == 0)
                        FabricaComandosPoliza.ObtenerComandoEnviarCorreo(dias, contrato).Ejecutar();
                    else if (dias <= 30)
                        FabricaComandosPoliza.ObtenerComandoEnviarCorreo(dias, contrato).Ejecutar();
                }
            }

            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion
        }


        /// <summary> Metodo que envia los correos de los contratos que estan por vencerce </summary>
        public void EnviarCorreos()
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion

            var lista = ConsultarContrato(new Contrato {Estado = 1});

            EnviarCorreoContratos(lista);
            EnviarCorreoPolizas(lista);

            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion

        }


        /// <summary> Metodo que consulta todos los establecimientos libres dentro de un limite de fecha </summary>
        /// <param name="inicio"> </param>
        /// <param name="fin">fecha de inicio de la busqueda</param>
        /// <returns>Lista de establecimientos que concuerdan con la fecha</returns>
        public IList<Establecimiento> ConsultarEstablecimientosLibres(DateTime inicio, DateTime fin)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<IList<Establecimiento>> comando = FabricaComandosEstablecimiento.ObtenerComandoConsultarEstablecimientosLibres(inicio,fin);
            var retorno = comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }

        /// <summary> Metodo que Agrega la Venta de un contrato </summary>
        /// <param name="venta">Datos Para la insercion</param>
        /// <returns>true si realizo la insercion</returns>
        public bool AgregarEditarVenta(Venta venta)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion

            IComando<bool> comando = FabricaComandosVentas.ObtenerComandoAgregarEditar(venta);
            var retorno = comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metodo que Consulta la lista de Venta de un contrato </summary>
        /// <param name="contrato">Datos Para la consulta</param>
        /// <param name="fechaInicio"> </param>
        /// <param name="fechaFin"> </param>
        /// <returns>Lista de Ventas del contrato</returns>
        public List<Venta> ConsultarVentasContratos(Contrato contrato, DateTime fechaInicio, DateTime fechaFin)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion

            IComando<List<Venta>> comando = FabricaComandosVentas.ObtenerComandoConsultarXContrato(contrato, fechaInicio,fechaFin);
            var retorno = comando.Ejecutar();

            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metood que consulta la lista de poliza segun los parametros indicados </summary>
        /// <param name="contrato">Parametros para la busqueda</param>
        /// <returns>Lista de Poliza</returns>
        public List<Poliza> ConsultarListaPoliza(Contrato contrato)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion

            IComando<List<Poliza>> comando = FabricaComandosPoliza.ObtenerComandoConsultar(contrato);
            var retorno = comando.Ejecutar();

            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metodo que agrega o edita la proyeccion de un contrato </summary>
        /// <param name="listaNueva">Lista Nueva</param>
        /// <param name="listaVieja">Lista Vieja</param>
        /// <returns>true si realiza la operacion</returns>
        public bool AgregarEditarProyeccion(IList<Proyeccion> listaNueva, IList<Proyeccion> listaVieja)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion

            if (listaVieja != null)
                foreach (var comando in listaVieja.Select(FabricaComandosProyeccion.ObtenerComandoEliminar))
                    comando.Ejecutar();

            foreach (var comando in listaNueva.Select(FabricaComandosProyeccion.Agregar))
                comando.Ejecutar();
            
            const bool retorno = true;

            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metodo que obtiene la lista deproyeccion de un contrato </summary>
        /// <param name="contrato">datos para la conuslta</param>
        /// <returns>lista de proyeccion de un contrato</returns>
        public IList<Proyeccion> ConsultarProyeccion(Contrato contrato)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion
            var comando = FabricaComandosProyeccion.Consultar(contrato);
            var retorno = comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metodo que consulta los canon por contrato y por fecha </summary>
        /// <param name="contrato">Datos del contrato a consultar</param>
        /// <param name="fecha">fecha inicio de la consulta</param>
        /// <returns>Lista de canon</returns>
        public List<ContratoPension> ConsultarCanon(Contrato contrato, DateTime fecha)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion
            var comando = FabricaComandosContratoPension.ObtenerComandoConsultarXFecha(contrato,fecha);
            var retorno = comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion
            return retorno;
        }


        /// <summary> Metodo que con almacena los datos de un contrato nuevo </summary>
        /// <param name="contrato">datos del contrato a almacenar</param>
        /// <returns>true si realizo la insercion false sino</returns>
        public bool AgregarContrato(Contrato contrato)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<bool> comando = FabricaComandosContrato.ObtenerComandoAgregar(contrato);
            comando.Ejecutar();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return true;
        }


        /// <summary> Metodo que Actualiza los estados de aquellas entidades que poseen vecimiento dada su fecha </summary>
        public void ActualizarEstados()
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.EntrandoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion
            IComando<bool> comando = FabricaComandosContrato.ObtenerComandoVencerContratos();
            comando.Ejecutar();

            comando = FabricaComandosPoliza.ObtenerComandoVencerPolizas();
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo, MethodBase.GetCurrentMethod().Name));
            #endregion
        }
    }
}
